#ifndef OPERATOR_H
#define OPERATOR_H

#include <QList>
#include <QString>
#include "node.h"
#include "expressionlist.h"

class Operator : public Node
{
public:
	enum OperatorKind
	{
		Add,
		Sub,
		Mul,
		Path,
		Filter,
		Less,
		Greater,
		Equal,
		NotEqual,
		GreaterOrEqual,
		LessOrEqual,
		And,
		Or,
		Div,
		Neg,
		Not,
		Power,
		Metric,
		Index,
		Call,
		Constant,
        Range,
        Dot,
        DotCall,
        If
	};
	
	OperatorKind operatorKind() const { return m_kind; }
	
protected:
    Operator(OperatorKind kind, const YYLTYPE& loc) : Node(loc), m_kind(kind) { }
	
private:
	OperatorKind m_kind;
};

class UnaryOperator : public Operator
{
public:
    UnaryOperator( Node* arg, OperatorKind kind, const YYLTYPE& loc ) : Operator( kind, loc ), m_arg( arg ) {
		appendChild( arg );
	}
	
	Node* argument() const { return m_arg; }

    virtual Type type();
    virtual void resolveAll();

private:
	Node* m_arg;
};

class BinaryOperator : public Operator
{
public:
    BinaryOperator( Node* arg1, Node* arg2, OperatorKind kind, const YYLTYPE& loc ) : Operator(kind, loc), m_arg1( arg1 ), m_arg2( arg2 ) {
		appendChild( arg1 ); appendChild( arg2 );
	}
	
	Node* firstArgument() const { return m_arg1; }
	Node* secondArgument() const { return m_arg2; }

    virtual Type type();
    virtual void resolveAll();

private:
	Node* m_arg1;
	Node* m_arg2;
};

class ExpressionList;
class Function;

class CallOperator : public Operator
{
public:
    CallOperator( const QString& ident, ExpressionList* callArgs, const YYLTYPE& loc ) : Operator( Operator::Call, loc ), m_identifier(ident), m_callArgs( callArgs ) {
		appendChild( m_callArgs );
	}
	
	ExpressionList* callArgs() const { return m_callArgs; }
    QString identifier() const { return m_identifier; }
    Function* resolvedFunction() const { return m_resolvedFunction; }

    virtual void resolveAll();
    virtual Type type();

private:
	QString m_identifier;
	ExpressionList* m_callArgs;
    Function* m_resolvedFunction;
};

class MetricOperator : public Operator
{
public:
    MetricOperator( Node* arg, const QString& metric, const YYLTYPE& loc ) : Operator( Operator::Metric, loc ), m_arg( arg ), m_metric( metric ) {
		appendChild( arg );
	}
	
	Node* argument() const { return m_arg; }
	QString metric() const { return m_metric; }
	    
private:
	Node* m_arg;
	QString m_metric;
};

class RangeOperator : public Operator
{
public:
    RangeOperator( Node* left, Node* right, const YYLTYPE& loc ) : Operator(Operator::Range, loc), m_left( left ), m_right( right ) {
        if ( left ) appendChild( left ); if ( right ) appendChild( right );
	}
	
	Node* leftBoundary() const { return m_left; }
	Node* rightBoundary() const { return m_right; }

    virtual Type type();
    virtual void resolveAll();

private:
	Node* m_left;
	Node* m_right;
};

class PathOperator : public Operator
{
public:
    PathOperator( Node* firstElement, Node* secondElement, const YYLTYPE& loc );

    QList<Node*> expressions() const;

    virtual Type type();
};

class DotOperator : public Operator
{
public:
    DotOperator( Node* arg, const QString& identifier, const YYLTYPE& loc );

    Node* argument() const { return m_arg; }
    QString identifier() const { return m_identifier; }

    virtual Type type();

private:
    Node* m_arg;
    QString m_identifier;
};

class DotCallOperator : public Operator
{
public:
    DotCallOperator( Node* obj, const QString& ident, ExpressionList* callArgs, const YYLTYPE& loc ) : Operator( Operator::DotCall, loc ), m_object(obj), m_identifier(ident), m_callArgs( callArgs ) {
        appendChild( m_object ); appendChild( m_callArgs );
    }

    Node* object() const { return m_object; }
    QString identifier() const { return m_identifier; }

    ExpressionList* callArgs() const { return m_callArgs; }

    virtual void resolveAll();
    virtual Type type();

private:
    Node* m_object;
    QString m_identifier;
    ExpressionList* m_callArgs;
};

class IfOperator : public Operator
{
public:
    IfOperator( Node* condition, Node* if_clause, Node* else_clause, const YYLTYPE& loc ) : Operator( Operator::If, loc ), m_condition(condition), m_if(if_clause), m_else(else_clause) {
        appendChild( condition ); appendChild( m_if ); appendChild( m_else );
    }

    Node* condition() const { return m_condition; }
    Node* ifClause() const { return m_if; }
    Node* elseClause() const { return m_else; }

private:
    Node* m_condition;
    Node* m_if;
    Node* m_else;
};

#endif
